#ifndef _GWBASE_AES_HELPER_H_
#define _GWBASE_AES_HELPER_H_

#include <string>
#include <openssl/evp.h>
#include <gwbase/base/util.h>
#include "gwbase/byte_array.h"
#include "gwbase/stopping_flag.h"
#include "gwbase/encrypt/compress_helper.h"

namespace dicom {

class IStoppingFlag;

class Aes256Encrypt
{
public:
	Aes256Encrypt(const ByteArray &key, size_t block_size);
	virtual ~Aes256Encrypt();

	bool Update(const uint8_t *data, size_t inlen);
	bool Finalize();

	const uint8_t *data() { return out_; }
	const uint8_t *end() { return out_ + outlen_; }
	int len() { return outlen_; }

private:
	EVP_CIPHER_CTX *ctx_;
	size_t block_size_;
	uint8_t *out_;
	int outlen_;
};

class Aes256Decrypt
{
public:
	Aes256Decrypt(const ByteArray &key, size_t block_size);
	virtual ~Aes256Decrypt();

	virtual bool Update(const uint8_t *data, size_t inlen);
	virtual bool Finalize();

	const uint8_t *data() { return out_; }
	const uint8_t *end() { return out_ + outlen_; }
	int len() { return outlen_; }

private:
	EVP_CIPHER_CTX *ctx_;
	size_t block_size_;
	uint8_t *out_;
	int outlen_;
};

class Aes128Encrypt
{
public:
	Aes128Encrypt(const ByteArray &key, size_t block_size);
	virtual ~Aes128Encrypt();

	bool Update(const uint8_t *data, size_t inlen);
	bool Finalize();

	const uint8_t *data() { return out_; }
	const uint8_t *end() { return out_ + outlen_; }
	int len() { return outlen_; }

private:
	EVP_CIPHER_CTX *ctx_;
	size_t block_size_;
	uint8_t *out_;
	int outlen_;
};

class Aes128Decrypt
{
public:
	Aes128Decrypt(const ByteArray &key, size_t block_size);
	virtual ~Aes128Decrypt();

	virtual bool Update(const uint8_t *data, size_t inlen);
	virtual bool Finalize();

	const uint8_t *data() { return out_; }
	const uint8_t *end() { return out_ + outlen_; }
	int len() { return outlen_; }

private:
	EVP_CIPHER_CTX *ctx_;
	size_t block_size_;
	uint8_t *out_;
	int outlen_;
};

enum AesMode {
	kAes128 = 128,
	kAes256 = 256,
};

class AESHelper
{
public:
	static ByteArray Encrypt256(const ByteArray &key, const ByteArray &plain);
	static ByteArray Encrypt128(const ByteArray &key, const ByteArray &plain);

	static ByteArray Decrypt256(const ByteArray &key, const ByteArray &cipher);
	static ByteArray Decrypt128(const ByteArray &key, const ByteArray &cipher);

	static Status EncFile(const ByteArray &key, const std::string &in, const std::string &out, IStoppingFlag *stop = NULL);
	static Status DecFile(const ByteArray &key, const std::string &in, const std::string &out, IStoppingFlag *stop = NULL);

	// 解密并解压缩文件，AES256解密+Deflate解压
	static Status DecAndUncompressFile(const ByteArray &key, const std::string &in, const std::string &out, IStoppingFlag *stop = NULL);
	static Status CompressAndEncFile(const ByteArray &key, const std::string &in, const std::string &out, 
		std::string *enc_sha1, std::string* src_md5, IStoppingFlag *stop = NULL);

	static ByteArray DecryptPrivateKey(const std::string &plain_pwd, const ByteArray &pk_cipher);
	static ByteArray EncryptPrivateKey(const std::string &plain_pwd, const ByteArray &pk_plain);
};
}

#endif // _GWBASE_AES_HELPER_H_
